package com.zklh.leetcode.structure.other;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;

/**
 * 推特算法实现
 *
 * @author 坐看落花
 * @version 1.0
 * @date 2021/7/25 13:02
 */
public class Twitter {


    private static class User{

        private static Map<Integer,User> userTables = new ConcurrentHashMap<>();

        private int id;

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            User user = (User) o;
            return id == user.id;
        }

        public User(int id) {
            this.id = id;
        }

        @Override
        public int hashCode() {
            return Objects.hash(id);
        }

        public static User getInstance(int id) {
            if (userTables.containsKey(id)) {
                return userTables.get(id);
            } else {
                User u = new User(id);
                userTables.put(id, u);
                // 初始化 userFolloweeMap, 并且自己关注自己
                userFolloweeMap.put(u, new HashSet<User>());
                userFolloweeMap.get(u).add(u);
                return u;
            }
        }

        public static boolean hasInstance(int id) {
            return userTables.containsKey(id);
        }
    }

    private static class Tweet{
        // id
        private int id;
        // 作者id
        private int authorId;
        // 发布时间
        private long createTime;

        private Tweet next;

        public Tweet(int id, int authorId, long createTime) {
            this.id = id;
            this.authorId = authorId;
            this.createTime = createTime;
        }
    }

    // 用户发布推文 map, tweet是一个链表, 第一个节点一定是最新发布的推文
    private static Map<User, Tweet> userTweetMap = new HashMap<>();
    // 用户关注的其他map
    private static Map<User, Set<User>> userFolloweeMap = new HashMap<>();

    /**
     * 发布推文
     * @param userId
     * @param tweetId
     */
    public void postTweet(int userId, int tweetId) {
        User u = User.getInstance(userId);
        long now = System.currentTimeMillis();
        Tweet tweet = new Tweet(tweetId, u.id, now);
        tweet.next = userTweetMap.get(u.id);
        userTweetMap.put(u, tweet);
    }

    /**
     * 获取userId自己和自己关注人的推文
     * @param userId
     * @return
     */
    public List<Integer> getNewsFee(int userId) {
        List<Integer> result = new ArrayList<>();

        User follower = User.getInstance(userId);
        // 先获取userId关注的用户
        Set<User> followees = userFolloweeMap.get(follower);

        PriorityQueue<Tweet> pq = new PriorityQueue<>(new Comparator<Tweet>() {
            @Override
            public int compare(Tweet o1, Tweet o2) {
                return Long.compare(o2.createTime,o1.createTime);
            }
        });

        for (User followee : followees) {
            if (userTweetMap.get(followee) != null) {
                pq.add(userTweetMap.get(followee));
            }
        }

        int defaultSize = 10;
        int capacity = defaultSize;
        while (!pq.isEmpty()) {
            if (capacity == 0) {
                break;
            }
            capacity--;
            Tweet tweet = pq.poll();
            result.add(tweet.id);
            if (tweet.next != null) {
                pq.add(tweet.next);
            }
        }
        return result;
    }

    /**
     * 设置关注
     * @param followerId 关注者
     * @param followeeId 被关注者
     */
    public void follow(int followerId, int followeeId) {
        User follower = User.getInstance(followerId);
        User followee = User.getInstance(followeeId);
        userFolloweeMap.get(follower).add(followee);
    }

    /**
     * 取消关注
     * @param followerId
     * @param followeeId
     */
    public void unFollow(int followerId, int followeeId) {
        if (!User.hasInstance(followerId)) {
            return;
        }

        if (followeeId == followerId) {
            return;
        }

        User follower = User.getInstance(followerId);
        User followee = User.getInstance(followeeId);


        if (userFolloweeMap.containsKey(follower)) {
            userFolloweeMap.get(follower).remove(followee);
        }
    }


    public static void main(String[] args) {
        Twitter twitter = new Twitter();

        twitter.postTweet(1,5);
        List<Integer> newsFee = twitter.getNewsFee(1);

        twitter.follow(1,2);
        twitter.postTweet(2,6);
        List<Integer> newsFee1 = twitter.getNewsFee(1);

        twitter.unFollow(1,2);
        List<Integer> newsFee2 = twitter.getNewsFee(1);



    }

}
